﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Implementation;
using Wrapper;
using Interfaces;
using System.Xml.Serialization;

/**
 * 
 * \file CarteImpl.cs
 * \brief Represente l'implementation de la carte
 * \author Baptiste Villiot - Jonathan Langlais
 * \version 1.0
 * 
 */
namespace civilisationLib.GeneratedCode.Implementation
{
    /**
    * 
    * \class CarteImpl
    * \brief Implementation d'une carte
    * 
    * classe abstraite de la carte
   */
    public abstract class CarteImpl : Carte
    {
        /**
         * !< la fabrique de case associee
         */
        public virtual FabriqueCaseImpl fabriqueCaseImpl
        {
            get;
            set;
        }

        /**
         * !< Contient les cases et leur positions
         */
        public static Dictionary<Tuple<int, int>, Case> caseDic
        {
            get;
            set;
        }

        /**
         * !< le wrapper
         */
        protected WrapperCivil c;

        /**
         * \fn void creer()
         * \brief initialise la carte
         */
        unsafe public virtual void creer()
        {
            int** pointeur = stackalloc int*[3];
            for (int i = 0; i < 3; i++)
            {
                int* temp = stackalloc int[2];
                temp[0] = fabriqueCaseImpl.caseDeco[i][0];
                temp[1] = fabriqueCaseImpl.caseDeco[i][1];
                pointeur[i] = temp;
            }
            //fixed (int** pointeur = fabriqueCaseImpl.caseDeco)
            {
                int** tab = null;
                c = new WrapperCivil(this.getTaille(), pointeur, FabriqueCaseImpl.NBDECO);
                tab = c.creerCarte();

                for (int i = 0; i < this.getTaille(); i++)
                {
                    for (int j = 0; j < this.getTaille(); j++)
                    {
                        caseDic.Add(new Tuple<int, int>(i, j), fabriqueCaseImpl.creerCases(tab[i][j]));
                    }
                }
            }
        }

        /**
         * \fn List<int> ressources()
         * \brief retourne la liste des ressources de toutes les cases
         * \return la liste contenant les ressources de toutes les cases
         */
        public List<int> ressources()
        {
            List<int> ressources = new List<int>();
            foreach (Case c in caseDic.Values)
            {
                int min = c.valMinerai() + c.valNourriture();
                ressources.Add(min);
            }
            return ressources;
        }

        /**
         * \fn int** suggestion()
         * \brief Suggestion des cases ideales pour creer une ville
         * \return le tableau contenant les positions
         */
        unsafe public List<Tuple<int, int>> suggestion()
        {
            List<Tuple<int, int>> listUnites = MonteurPartieImpl.joueurCourant.unitesEnnemies(this.getTaille());
            List<Tuple<int, int>> listVilles = MonteurPartieImpl.joueurCourant.villesEnnemies();
            List<int> r = ressources();
            int** tab = stackalloc int*[this.getTaille()];
            int** res = null;
            int* ress = stackalloc int[this.getTaille() * this.getTaille()];

            for (int i = 0; i < this.getTaille() * this.getTaille(); i++)
            {
                ress[i] = r.First();
                r.Remove(r.First());
            }


            for (int i = 0; i < this.getTaille(); i++)
            {
                int* soustab = stackalloc int[this.getTaille()];
                tab[i] = soustab;

            }
            for (int i = 0; i < this.getTaille(); i++)
            {
                for (int j = 0; j < this.getTaille(); j++)
                {
                    tab[i][j] = 0;
                }
            }
            foreach (Tuple<int, int> t in listUnites)
            {
                tab[t.Item1][t.Item2] = 1;
            }

            foreach (Tuple<int, int> t in listVilles)
            {
                tab[t.Item1][t.Item2] = 2;
            }

            for (int i = 0; i < this.getTaille() * this.getTaille(); i++)
            {
                Console.Write(ressources()[i] + ",");
            }

            res = c.suggestion(tab, ress);

            List<Tuple<int, int>> sug = new List<Tuple<int, int>>();
            for (int i = 0; i < 3; i++)
            {
                Tuple<int, int> tu = new Tuple<int, int>(res[i][0], res[i][1]);
                sug.Add(tu);
            }
            return sug;
        }

        /**
         * \fn int getTaille()
         * \brief retourne la taille de la carte
         * \return la la taille de la carte
         */
        public abstract int getTaille();

        /**
         * \fn Dictionary<Tuple<int, int>, Case> getCaseDic()
         * \brief Permet de recuperer les cases et leur position
         * \return le dictionnaire (cases et position)
         */
        public abstract Dictionary<Tuple<int, int>, Case> getCaseDic();

        /**
         * \fn public System.Xml.Schema.XmlSchema GetSchema()
         * \brief Retourne le schema XML
         */
        public System.Xml.Schema.XmlSchema GetSchema()
        {
            return null;
        }

        /**
         * \fn public void ReadXml(System.Xml.XmlReader reader)
         * \brief Lecture du fichier de sauvegarde
         * \param[in] le lecteur
         */
        public void ReadXml(System.Xml.XmlReader reader)
        {
            XmlSerializer serial;
            reader.ReadStartElement();
            serial = new XmlSerializer(typeof(FabriqueCaseImpl));
            reader.ReadStartElement();
            this.fabriqueCaseImpl = serial.Deserialize(reader) as FabriqueCaseImpl;
            reader.ReadEndElement();
            reader.ReadEndElement();
            string nb = reader.GetAttribute("nb");
            int number = int.Parse(nb);
            reader.ReadStartElement();
            for (int i = 0; i < number; i++)
            {
                reader.ReadStartElement();
                reader.ReadStartElement();
                reader.ReadStartElement();
                serial = new XmlSerializer(typeof(int));
                int item1 = (int)serial.Deserialize(reader);
                reader.ReadEndElement();
                reader.ReadStartElement();
                int item2 = (int)serial.Deserialize(reader);
                reader.ReadEndElement();
                reader.ReadEndElement();
                reader.ReadStartElement();
                serial = new XmlSerializer(typeof(int));
                int caseType = (int)serial.Deserialize(reader);
                caseDic.Add(new Tuple<int, int>(item1, item2), fabriqueCaseImpl.creerCases(caseType));
                reader.ReadEndElement();
                reader.ReadEndElement();
            }
            reader.ReadEndElement();
        }

        /**
         * \fn public void WriteXml(System.Xml.XmlWriter reader)
         * \brief Ecriture du fichier de sauvegarde
         * \param[in] l'ecrivain
         */
        public void WriteXml(System.Xml.XmlWriter writer)
        {
            XmlSerializer serial;
            writer.WriteStartElement("fabriqueCase");
            serial = new XmlSerializer(fabriqueCaseImpl.GetType());
            serial.Serialize(writer, fabriqueCaseImpl);
            writer.WriteEndElement();

            writer.WriteStartElement("caseDicCarte");
            writer.WriteAttributeString("nb", "" + caseDic.Count);
            foreach (KeyValuePair<Tuple<int, int>, Case> t in this.getCaseDic())
            {
                writer.WriteStartElement("case");
                writer.WriteStartElement("position");
                writer.WriteStartElement("item1");
                serial = new XmlSerializer(typeof(int));
                serial.Serialize(writer, t.Key.Item1);
                writer.WriteEndElement();
                writer.WriteStartElement("item2");
                serial = new XmlSerializer(typeof(int));
                serial.Serialize(writer, t.Key.Item2);
                writer.WriteEndElement();
                writer.WriteEndElement();
                writer.WriteStartElement("value");
                serial = new XmlSerializer(typeof(int));
                serial.Serialize(writer, t.Value.getTypeCase());
                writer.WriteEndElement();
                writer.WriteEndElement();
            }
            writer.WriteEndElement();
        }
    }
}
